﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Threading;
using BrasilFramework.Controle.Silverlight.Comum;

namespace BrasilFramework.Controle.Silverlight
{
    public class Menu : Grid
    {
        #region attributes

        public readonly DependencyProperty MenuItemProperty;
        public readonly DependencyProperty CommandProperty;
        public readonly DependencyProperty BorderBrushProperty;
        public readonly DependencyProperty TopPanelBrushProperty;
        public readonly DependencyProperty ImageBackgroundBrushProperty;
        public readonly DependencyProperty FocusBrushProperty;
        public readonly DependencyProperty FocusBorderBrushProperty;
        public readonly DependencyProperty ForegroundProperty;
        public new readonly DependencyProperty BackgroundProperty;

        private readonly StackPanel stackPanel = new StackPanel();
        private static readonly Dictionary<string, MenuItem> menuDictionary = new Dictionary<string, MenuItem>();

        private Brush borderBrush = new SolidColorBrush(Color.FromArgb(0xFF, 0x9E, 0xA9, 0xBD));
        private Brush topPanelBrush;
        private Brush imageBackgroundBrush = new SolidColorBrush(Color.FromArgb(0xFF, 0xD8, 0xE1, 0xF0));
        private Brush focusBrush;
        private Brush focusBorderBrush = new SolidColorBrush(Color.FromArgb(0xFF, 0xF5, 0xC3, 0x65));
        private Brush foreground = new SolidColorBrush(Colors.Black);
        private Brush background = new SolidColorBrush(Color.FromArgb(0xFF, 0xC8, 0xD1, 0xE0));
        private const double verticalMenuWidth = 200;
        private static int selectedMenuLevel;
        private ICommand command;
        public event EventHandler MenuItemClicked;
        private bool isOverMenu;

        #endregion attributes

        #region constructor

        public Menu()
        {
            SetValue(Canvas.ZIndexProperty, 1000);
            MenuItemProperty =
                DependencyProperty.Register("MenuItem", typeof(MenuItem), typeof(Menu),
                                            new PropertyMetadata(null,
                                                                 OnMenuItemChanged));

            CommandProperty =
                DependencyProperty.Register("Command", typeof(ICommand), typeof(Menu),
                                            new PropertyMetadata(null,
                                                                 OnCommandChanged));

            BorderBrushProperty =
                DependencyProperty.Register("BorderBrush", typeof(Brush), typeof(Menu),
                                            new PropertyMetadata(null,
                                                                 OnBorderBrushChanged));

            TopPanelBrushProperty =
                DependencyProperty.Register("TopPanelBrush", typeof(Brush), typeof(Menu),
                                            new PropertyMetadata(null,
                                                                 OnTopPanelBrushChanged));

            ImageBackgroundBrushProperty =
                DependencyProperty.Register("ImageBackgroundBrush", typeof(Brush), typeof(Menu),
                                            new PropertyMetadata(null,
                                                                 OnImageBackgroundBrushChanged));

            FocusBrushProperty =
                DependencyProperty.Register("FocusBrush", typeof(Brush), typeof(Menu),
                                            new PropertyMetadata(null,
                                                                 OnFocusBrushChanged));

            FocusBorderBrushProperty =
                DependencyProperty.Register("FocusBorderBrush", typeof(Brush), typeof(Menu),
                                            new PropertyMetadata(null,
                                                                 OnFocusBorderBrushChanged));

            ForegroundProperty =
                DependencyProperty.Register("Foreground", typeof(Brush), typeof(Menu),
                                            new PropertyMetadata(null,
                                                                 OnForegroundChanged));

            BackgroundProperty =
                DependencyProperty.Register("Background", typeof(Brush), typeof(Menu),
                                            new PropertyMetadata(null,
                                                                 OnBackgroundChanged));

            LinearGradientBrush lgb = new LinearGradientBrush { StartPoint = new Point(0, 0), EndPoint = new Point(0, 1) };

            lgb.GradientStops.Add(new GradientStop { Offset = 0.0, Color = Color.FromArgb(0xFF, 0xC8, 0xD1, 0xE0) });
            lgb.GradientStops.Add(new GradientStop { Offset = 1.0, Color = Color.FromArgb(0xFF, 0x9E, 0xA9, 0xBD) });

            topPanelBrush = lgb;

            LinearGradientBrush lgb2 = new LinearGradientBrush { StartPoint = new Point(0, 0), EndPoint = new Point(0, 1) };

            lgb2.GradientStops.Add(new GradientStop { Offset = 0.0, Color = Color.FromArgb(0xFF, 0xFF, 0xFB, 0xF1) });
            lgb2.GradientStops.Add(new GradientStop { Offset = 1.0, Color = Color.FromArgb(0xFF, 0xFF, 0xDC, 0xA5) });

            focusBrush = lgb2;

            stackPanel.Orientation = Orientation.Horizontal;
            stackPanel.Background = topPanelBrush;
            stackPanel.Height = 22;
            stackPanel.VerticalAlignment = VerticalAlignment.Top;
            stackPanel.SetValue(Canvas.ZIndexProperty, -5000);
            Children.Add(stackPanel);

            MouseEnter += (s1, e1) => { timerMouseOver.Stop(); isOverMenu = true; };

            MouseLeave += (s2, e2) => { timerMouseOver.Start(); isOverMenu = false; };

            Loaded += (s3, e3) =>
                          {
                              FrameworkElement parent = (FrameworkElement)Parent;

                              parent.MouseLeftButtonUp += (s4, e4) =>
                                                              {
                                                                  if (isOverMenu) return;

                                                                  HideOpenedMenu();
                                                                  selectedMenuLevel = 0;
                                                              };

                              IntializeTimeMouseOver();
                          };
        }

        #endregion constructor

        #region Methods

        public void ClearReferences(MenuItem menuItem)
        {
            foreach (MenuItem childMenuItem in menuItem.Children)
            {
                ClearReferences(childMenuItem);
            }
            if (menuItem.MenuGrid != null)
            {
                menuItem.MenuGrid.Tag = null;
                menuItem.MenuGrid = null;
            }
        }

        public void AddMenuItem(MenuItem parent, MenuItem child)
        {
            menuDictionary["mnuRecentFiles"].Children.Add(child);
            stackPanel.Children.Clear();
            ClearReferences(MenuItem);
            menuDictionary.Clear();
            DrawMenu(this, MenuItem);
        }

        private int menuIndex;

        private void DrawMenu(Menu menu, MenuItem menuItem)
        {
            if (menuItem == null)
                return;

            double currentLeftMargin = 0;
            foreach (MenuItem mi2 in menuItem.Children)
            {

                if (string.IsNullOrEmpty(menuItem.Name))
                    menuItem.Name = "menu" + ++menuIndex;

                mi2.ParentName = menuItem.Name;
                mi2.Level = menuItem.Level + 1;

                const double currentTopMargin = 0;
                TextBlock textBlockLevel1 = new TextBlock
                                                {
                                                    Text = mi2.Text,
                                                    Margin = new Thickness(8, 4, 8, 4),
                                                    VerticalAlignment = VerticalAlignment.Center,
                                                    Foreground = foreground
                                                };

                //var fill = new LinearGradientBrush() { StartPoint = new Point(0, 0), EndPoint = new Point(0, 1) };
                //fill.GradientStops.Add(new GradientStop() { Offset = 0.0, Color = Color.FromArgb(0xFF, 0xFF, 0xFB, 0xF1) });
                //fill.GradientStops.Add(new GradientStop() { Offset = 1.0, Color = Color.FromArgb(0xFF, 0xFF, 0xDC, 0xA5) });

                Rectangle focusRectangle1 = new Rectangle
                                                {
                                                    Fill = focusBrush,
                                                    HorizontalAlignment = HorizontalAlignment.Stretch,
                                                    VerticalAlignment = VerticalAlignment.Stretch,
                                                    Visibility = Visibility.Collapsed,
                                                    Margin = new Thickness(2, 2, 2, 2),
                                                    RadiusX = 2,
                                                    RadiusY = 2
                                                };

                Rectangle focusRectangle2 = new Rectangle
                                                {
                                                    Stroke = focusBorderBrush,
                                                    HorizontalAlignment = HorizontalAlignment.Stretch,
                                                    VerticalAlignment = VerticalAlignment.Stretch,
                                                    Visibility = Visibility.Collapsed,
                                                    Margin = new Thickness(2, 2, 2, 2),
                                                    RadiusX = 2,
                                                    RadiusY = 2
                                                };

                Grid gridLevel1 = new Grid();

                gridLevel1.Children.Add(focusRectangle1);
                gridLevel1.Children.Add(textBlockLevel1);
                gridLevel1.Children.Add(focusRectangle2);

                if (string.IsNullOrEmpty(mi2.Name))
                    mi2.Name = "menu" + ++menuIndex;

                gridLevel1.Tag = mi2.Name;

                gridLevel1.MouseEnter += grid_MouseEnter;
                gridLevel1.MouseLeave += grid_MouseLeave;
                gridLevel1.MouseLeftButtonUp += gridLevel1_MouseLeftButtonUp;

                menu.stackPanel.Children.Add(gridLevel1);

                //LinearGradientBrush bkg = new LinearGradientBrush() { StartPoint = new Point(0, 0), EndPoint = new Point(0, 1) };
                //bkg.GradientStops.Add(new GradientStop() { Offset = 0.0, Color = Color.FromArgb(0xFF, 0xD8, 0xE1, 0xF0) });

                TextBlock txt = new TextBlock
                                    {
                                        Text = mi2.Text,
                                        Margin = new Thickness(7, 1, 8, 4),
                                        VerticalAlignment = VerticalAlignment.Center,
                                        Foreground = foreground
                                    };

                Border brd = new Border
                                 {
                                     CornerRadius = new CornerRadius(2),
                                     BorderBrush = borderBrush,
                                     BorderThickness = new Thickness(1),
                                     HorizontalAlignment = HorizontalAlignment.Stretch,
                                     VerticalAlignment = VerticalAlignment.Stretch,
                                     Margin = new Thickness(0, 2, 0, 0)
                                 };


                Grid grdVertical = null;

                //grdVertical = CreateVerticalGrid(menu, currentLeftMargin, currentTopMargin, mi2, focusBrush, txt, grdVertical);
                grdVertical = CreateVerticalGrid(menu, currentLeftMargin, currentTopMargin, mi2, txt, grdVertical);

                currentLeftMargin += textBlockLevel1.ActualWidth + 16;
            }
        }

        private Grid CreateVerticalGrid(
            Grid parentGrid,
            double currentLeftMargin,
            double currentTopMargin,
            MenuItem parentMenuItem,
            TextBlock txt,
            Grid grdVertical)
        {
            Grid verticalGrid = new Grid
                                    {
                                        Width = verticalMenuWidth,
                                        HorizontalAlignment = HorizontalAlignment.Left,
                                        VerticalAlignment = VerticalAlignment.Top
                                    };

            grdVertical = new Grid
                              {
                                  Margin = new Thickness(currentLeftMargin, currentTopMargin, 0, 0),
                                  HorizontalAlignment = HorizontalAlignment.Left,
                                  VerticalAlignment = VerticalAlignment.Top
                              };
            grdVertical.RowDefinitions.Add(new RowDefinition { Height = new GridLength(22) });
            grdVertical.RowDefinitions.Add(new RowDefinition { Height = new GridLength(22) });

            parentGrid.Children.Add(grdVertical);

            parentMenuItem.MenuGrid = grdVertical;

            Border brdAroundVerticalParent = new Border
                                                 {
                                                     Margin = new Thickness(0, 1, 0, 0),
                                                     CornerRadius = new CornerRadius(2),
                                                     BorderBrush = borderBrush,
                                                     BorderThickness = new Thickness(1),
                                                     Background = background,
                                                     Height = 22,
                                                     HorizontalAlignment = HorizontalAlignment.Left,
                                                     VerticalAlignment = VerticalAlignment.Top,
                                                     RenderTransform = new TranslateTransform {Y = 0}
                                                 };
            brdAroundVerticalParent.SetValue(RowProperty, 0);
            brdAroundVerticalParent.SetValue(Canvas.ZIndexProperty, parentMenuItem.Level * 100);

            if (parentMenuItem.Level == 1)
                brdAroundVerticalParent.Child = txt;

            if (parentMenuItem.Level > 1)
                brdAroundVerticalParent.Visibility = Visibility.Collapsed;

            brdAroundVerticalParent.MouseLeftButtonUp += brdAroundVerticalParent_MouseLeftButtonUp;

            grdVertical.Children.Add(brdAroundVerticalParent);

            Border brdAroundVerticalChildren = new Border
                                                   {
                                                       CornerRadius = new CornerRadius(2),
                                                       BorderBrush = borderBrush,
                                                       BorderThickness = new Thickness(1),
                                                       HorizontalAlignment = HorizontalAlignment.Left,
                                                       VerticalAlignment = VerticalAlignment.Top,
                                                       Child = verticalGrid,
                                                       RenderTransform = new TranslateTransform {Y = 0}
                                                   };

            brdAroundVerticalChildren.SetValue(RowProperty, 1);

            grdVertical.Children.Add(brdAroundVerticalChildren);
            Rectangle rectHideLine = new Rectangle
                                         {
                                             Margin = new Thickness(0, 0, 0, 0),
                                             HorizontalAlignment = HorizontalAlignment.Stretch,
                                             Stroke = background,
                                             VerticalAlignment = VerticalAlignment.Top,
                                             Height = 1
                                         };
            rectHideLine.SetValue(RowProperty, 1);
            Rectangle rectLineLeft = new Rectangle
                                         {
                                             Margin = new Thickness(0, 5, 0, 0),
                                             Fill = borderBrush,
                                             VerticalAlignment = VerticalAlignment.Top,
                                             HorizontalAlignment = HorizontalAlignment.Left,
                                             Width = 1,
                                             Height = 22
                                         };

            rectLineLeft.SetValue(RowProperty, 0);
            rectLineLeft.SetValue(RowSpanProperty, 2);

            if (parentMenuItem.Level < 2)
            {
                grdVertical.Children.Add(rectHideLine);
                grdVertical.Children.Add(rectLineLeft);
            }

            int gridRow = 0;
            foreach (MenuItem mi3 in parentMenuItem.Children)
            {
                mi3.ParentName = parentMenuItem.Name;
                mi3.Level = parentMenuItem.Level + 1;

                if (string.IsNullOrEmpty(mi3.Name))
                    mi3.Name = "menu" + ++menuIndex;

                Rectangle focusRectangle3 = new Rectangle
                                                {
                                                    Fill = focusBrush,
                                                    HorizontalAlignment = HorizontalAlignment.Stretch,
                                                    VerticalAlignment = VerticalAlignment.Stretch,
                                                    Visibility = Visibility.Collapsed,
                                                    Margin = new Thickness(1, 0, 10, 0),
                                                    RadiusX = 2,
                                                    RadiusY = 2
                                                };

                Rectangle focusRectangle4 = new Rectangle
                                                {
                                                    Stroke = focusBorderBrush,
                                                    HorizontalAlignment = HorizontalAlignment.Stretch,
                                                    VerticalAlignment = VerticalAlignment.Stretch,
                                                    Visibility = Visibility.Collapsed,
                                                    Margin = new Thickness(1, 0, 10, 0),
                                                    RadiusX = 2,
                                                    RadiusY = 2
                                                };

                Rectangle separatorRectangle = new Rectangle
                                                   {
                                                       Height = 1,
                                                       Fill =
                                                           new SolidColorBrush(Color.FromArgb(0xFF, 0xA0, 0xA0, 0xA0)),
                                                       HorizontalAlignment = HorizontalAlignment.Stretch,
                                                       VerticalAlignment = VerticalAlignment.Center,
                                                       Margin = new Thickness(2, 0, 2, 0)
                                                   };
                separatorRectangle.SetValue(ColumnProperty, 1);
                separatorRectangle.SetValue(ColumnSpanProperty, 2);

                Border brdImage = new Border
                                      {
                                          Width = 24,
                                          Height = 22,
                                          HorizontalAlignment = HorizontalAlignment.Left,
                                          Background = imageBackgroundBrush
                                      };
                Image imgLevel2 = new Image
                                      {
                                          Width = 16,
                                          Height = 16,
                                          HorizontalAlignment = HorizontalAlignment.Left,
                                          Margin = new Thickness(4, 0, 0, 0),
                                          Opacity = mi3.IsEnabled ? 1.0 : 0.5
                                      };
                imgLevel2.SetValue(ColumnProperty, 0);

                Image imgArrow = new Image
                                     {
                                         Width = 16,
                                         Height = 16,
                                         HorizontalAlignment = HorizontalAlignment.Left,
                                         Margin = new Thickness(0, 0, 0, 0),
                                         Opacity = mi3.IsEnabled ? 1.0 : 0.5
                                     };
                imgArrow.SetValue(ColumnProperty, 2);
                imgArrow.Source = Imagem.Arrow;
                imgArrow.Visibility = mi3.Children.Count > 0 ? Visibility.Visible : Visibility.Collapsed;

                if (mi3.IsCheckable)
                {
                    mi3.ImagePath = mi3.IsChecked ? Imagem.Checked : null;
                }
                else
                {
                    if (mi3.ImagePath == null)
                        mi3.ImagePath = mi3.ImagePath;
                }

                if (mi3.ImagePath != null)
                {
                    imgLevel2.Source = mi3.ImagePath;
                }

                TextBlock textBlockLevel2 = new TextBlock
                                                {
                                                    Text = mi3.Text,
                                                    Margin = new Thickness(8, 4, 8, 4),
                                                    VerticalAlignment = VerticalAlignment.Center,
                                                    Foreground = foreground,
                                                    Opacity = mi3.IsEnabled ? 1.0 : 0.5
                                                };

                Grid gridLevel2 = new Grid
                                      {
                                          Background = background
                                      };

                gridLevel2.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(24) });
                gridLevel2.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(verticalMenuWidth - 40) });
                gridLevel2.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(24), MinWidth = 24 });

                focusRectangle3.SetValue(ColumnProperty, 0);
                focusRectangle3.SetValue(ColumnSpanProperty, 3);

                textBlockLevel2.SetValue(ColumnProperty, 1);
                focusRectangle4.SetValue(ColumnProperty, 0);
                focusRectangle4.SetValue(ColumnSpanProperty, 3);

                verticalGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(22) });

                if (mi3.Text.Equals("-"))
                {
                    gridLevel2.Children.Add(brdImage);
                    gridLevel2.Children.Add(separatorRectangle);
                    verticalGrid.RowDefinitions[verticalGrid.RowDefinitions.Count - 1].Height = new GridLength(2);
                    separatorRectangle.SetValue(ColumnProperty, 1);
                    separatorRectangle.SetValue(ColumnSpanProperty, 2);
                }
                else
                {
                    gridLevel2.Children.Add(brdImage);
                    gridLevel2.Children.Add(focusRectangle3);
                    gridLevel2.Children.Add(imgLevel2);
                    gridLevel2.Children.Add(textBlockLevel2);
                    gridLevel2.Children.Add(imgArrow);
                    gridLevel2.Children.Add(focusRectangle4);

                    gridLevel2.MouseEnter += gridLevel2_MouseEnter;
                    gridLevel2.MouseLeave += gridLevel2_MouseLeave;
                    gridLevel2.MouseLeftButtonUp += gridLevel2_MouseLeftButtonUp;
                }
                gridLevel2.Tag = mi3;
                gridLevel2.SetValue(RowProperty, gridRow);
                verticalGrid.Children.Add(gridLevel2);

                grdVertical.RowDefinitions[1].Height = new GridLength(grdVertical.RowDefinitions[1].Height.Value + 22);
                gridRow++;


                if (mi3.Children.Count > 0)
                {
                    CreateVerticalGrid(parentGrid, currentLeftMargin + verticalMenuWidth, currentTopMargin, mi3, txt,
                                       grdVertical);
                }

                if (mi3.Text.Equals("-"))
                {
                    currentTopMargin += 2;
                }
                else
                {
                    currentTopMargin += 22;
                }

                if (!menuDictionary.ContainsKey(mi3.Name))
                    menuDictionary.Add(mi3.Name, mi3);
            }
            grdVertical.Visibility = Visibility.Collapsed;
            menuDictionary.Add(parentMenuItem.Name, parentMenuItem);

            grdVertical.SetValue(Canvas.ZIndexProperty, parentMenuItem.Level * 100);

            return grdVertical;
        }

        private void HideSiblings(MenuItem menuItem)
        {
            if (menuItem.ParentName == null) return;

            MenuItem parentMenuItem = menuDictionary[menuItem.ParentName];
            foreach (MenuItem siblingMenu in parentMenuItem.Children.Where(siblingMenu => siblingMenu.Name != menuItem.Name))
            {
                if (menuDictionary.ContainsKey(siblingMenu.Name))
                {
                    if (menuDictionary[siblingMenu.Name].MenuGrid != null)
                        menuDictionary[siblingMenu.Name].MenuGrid.Visibility = Visibility.Collapsed;
                }

                foreach (MenuItem child in siblingMenu.Children)
                {
                    HideSiblings(child);
                }
            }
        }

        #endregion Methods

        #region Properties

        public MenuItem MenuItem
        {
            get { return (MenuItem)GetValue(MenuItemProperty); }
            set { SetValue(MenuItemProperty, value); }
        }

        public ICommand Command
        {
            get { return (ICommand)GetValue(CommandProperty); }
            set { SetValue(CommandProperty, value); }
        }

        public Brush BorderBrush
        {
            get { return (Brush)GetValue(BorderBrushProperty); }
            set { SetValue(BorderBrushProperty, value); }
        }

        public Brush TopPanelBrush
        {
            get { return (Brush)GetValue(TopPanelBrushProperty); }
            set { SetValue(TopPanelBrushProperty, value); }
        }

        public Brush ImageBackgroundBrush
        {
            get { return (Brush)GetValue(ImageBackgroundBrushProperty); }
            set { SetValue(ImageBackgroundBrushProperty, value); }
        }

        public Brush FocusBrush
        {
            get { return (Brush)GetValue(FocusBrushProperty); }
            set { SetValue(FocusBrushProperty, value); }
        }

        public Brush FocusBorderBrush
        {
            get { return (Brush)GetValue(FocusBorderBrushProperty); }
            set { SetValue(FocusBorderBrushProperty, value); }
        }

        public Brush Foreground
        {
            get { return (Brush)GetValue(ForegroundProperty); }
            set { SetValue(ForegroundProperty, value); }
        }

        public new Brush Background
        {
            get { return (Brush)GetValue(BackgroundProperty); }
            set { SetValue(BackgroundProperty, value); }
        }

        #endregion Properties

        #region Events

        public void OnMenuItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Menu menu = (Menu)d;
            MenuItem menuItem = (MenuItem)e.NewValue;

            menu.stackPanel.Children.Clear();

            DrawMenu(menu, menuItem);
        }

        public void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            command = (ICommand)e.NewValue;
        }

        public void OnBorderBrushChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            borderBrush = (Brush)e.NewValue;
        }

        public void OnTopPanelBrushChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            topPanelBrush = (Brush)e.NewValue;
            stackPanel.Background = topPanelBrush;
        }

        public void OnImageBackgroundBrushChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            imageBackgroundBrush = (Brush)e.NewValue;
        }

        public void OnFocusBrushChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            focusBrush = (Brush)e.NewValue;
        }

        public void OnFocusBorderBrushChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            focusBorderBrush = (Brush)e.NewValue;
        }

        public void OnForegroundChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            foreground = (Brush)e.NewValue;
        }

        public void OnBackgroundChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            background = (Brush)e.NewValue;
        }

        private void brdAroundVerticalParent_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            Grid grid = (Grid)((Border)sender).Parent;
            grid.Visibility = Visibility.Collapsed;
            selectedMenuLevel = 0;
        }

        private void gridLevel2_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            selectedMenuLevel = 0;
            Grid grid = (Grid)sender;
            MenuItem menuItem = (MenuItem)grid.Tag;
            if (menuItem.IsEnabled)
            {
                foreach (KeyValuePair<string, MenuItem> item in menuDictionary.Where(item => item.Value.MenuGrid != null))
                {
                    item.Value.MenuGrid.Visibility = Visibility.Collapsed;
                }
            }

            if (menuItem.IsCheckable)
            {
                menuItem.IsChecked = !menuItem.IsChecked;

                Image img = (Image)(grid.Children[2]);
                img.Source = menuItem.IsChecked ? Imagem.Checked : null;
            }

            if (MenuItemClicked != null)
                MenuItemClicked(menuItem, new EventArgs());

            if (command != null)
                command.Execute(menuItem);
        }

        private void gridLevel2_MouseLeave(object sender, MouseEventArgs e)
        {
            Grid grid = (Grid)sender;
            grid.Children[1].Visibility = Visibility.Collapsed;
            grid.Children[5].Visibility = Visibility.Collapsed;
        }

        private void gridLevel2_MouseEnter(object sender, MouseEventArgs e)
        {
            Grid grid = (Grid)sender;
            MenuItem menuItem = (MenuItem)grid.Tag;

            if (menuItem.IsEnabled)
            {
                grid.Children[1].Visibility = Visibility.Visible;
                grid.Children[5].Visibility = Visibility.Visible;
            }

            if (menuItem.MenuGrid != null)
            {
                menuItem.MenuGrid.Visibility = Visibility.Visible;
            }

            HideSiblings(menuItem);
        }

        private static void HideOpenedMenu(bool setToRoot = false)
        {
            foreach (KeyValuePair<string, MenuItem> item in menuDictionary.Where(item => item.Value.MenuGrid != null))
            {
                item.Value.MenuGrid.Visibility = Visibility.Collapsed;
            }
            if(setToRoot) selectedMenuLevel = 0;
        }

        private void gridLevel1_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            Grid grid = (Grid) sender;
            MenuItem menuItem = menuDictionary[grid.Tag.ToString()];

            if (menuItem.MenuGrid.Visibility == Visibility.Collapsed)
            {
                if (!string.IsNullOrEmpty(menuItem.Command))
                {
                    HideOpenedMenu(true);
                    MenuItemClicked(menuItem, null);   
                }
                else if(menuItem.Children != null && menuItem.Children.Count > 0)
                {
                    menuItem.MenuGrid.Visibility = Visibility.Visible;
                    selectedMenuLevel = 1;
                }
            }
            else
            {
                menuItem.MenuGrid.Visibility = Visibility.Collapsed;
                selectedMenuLevel = 0;
            }
        }

        private DispatcherTimer timerMouseOver;

        private void IntializeTimeMouseOver()
        {
            timerMouseOver = new DispatcherTimer { Interval = new TimeSpan(0, 0, 1) };
            timerMouseOver.Tick += TimerMouseOverTick;
        }

        void TimerMouseOverTick(object sender, EventArgs e)
        {
            timerMouseOver.Stop();
            HideOpenedMenu(true);
        }

        private void grid_MouseLeave(object sender, MouseEventArgs e)
        {
            Grid grid = (Grid)sender;
            grid.Children[0].Visibility = Visibility.Collapsed;
            grid.Children[2].Visibility = Visibility.Collapsed;
        }


        private void grid_MouseEnter(object sender, MouseEventArgs e)
        {
            Grid grid = (Grid)sender;
            MenuItem menuItem = menuDictionary[grid.Tag.ToString()];

            if (selectedMenuLevel == 0)
            {
                grid.Children[0].Visibility = Visibility.Visible;
                grid.Children[2].Visibility = Visibility.Visible;
            }
            else if (menuItem.Children.Count > 0)
            {
                HideOpenedMenu();
                menuItem.MenuGrid.Visibility = Visibility.Visible;
            }
        }

        #endregion Events
    }

    [ContentProperty("Children")]
    public class MenuItem : ObservableCollection<MenuItem>
    {
        #region attributes

        private bool isEnabled = true;

        #endregion attributes

        #region Properties

        public IList<MenuItem> Children
        {
            get { return Items; }
            set
            {
                foreach (MenuItem item in value)
                {
                    Items.Add(item);
                }
            }
        }

        public string Name { get; set; }

        public string ParentName { get; set; }

        public string Text { get; set; }

        public string Command { get; set; }

        public BitmapImage ImagePath { get; set; }

        public bool IsEnabled
        {
            get { return isEnabled; }
            set { isEnabled = value; }
        }

        public bool IsCheckable { get; set; }

        public bool IsChecked { get; set; }

        public Grid MenuGrid { get; set; }

        public int Level { get; set; }

        #endregion Properties

        #region Methods

        public override string ToString()
        {
            return Name;
        }

        #endregion Methods
    }
}